/**
 * 对象工具类
 * 提供对象操作、类型判断和转换功能
 */
export default class ObjectUtil {
  /**
   * 判断对象是否为空
   * 
   * @param obj 对象
   * @returns 是否为空
   */
  public static isEmpty(obj: any): boolean {
    return obj === null || obj === undefined;
  }

  /**
   * 判断对象是否非空
   * 
   * @param obj 对象
   * @returns 是否非空
   */
  public static isNotEmpty(obj: any): boolean {
    return !this.isEmpty(obj);
  }

  /**
   * 判断对象是否为数组
   * 
   * @param obj 对象
   * @returns 是否为数组
   */
  public static isArray(obj: any): boolean {
    return Array.isArray(obj);
  }

  /**
   * 判断对象是否为对象类型
   * 
   * @param obj 对象
   * @returns 是否为对象类型
   */
  public static isObject(obj: any): boolean {
    return obj !== null && typeof obj === 'object' && !Array.isArray(obj);
  }

  /**
   * 判断对象是否为函数
   * 
   * @param obj 对象
   * @returns 是否为函数
   */
  public static isFunction(obj: any): boolean {
    return typeof obj === 'function';
  }

  /**
   * 判断对象是否为字符串
   * 
   * @param obj 对象
   * @returns 是否为字符串
   */
  public static isString(obj: any): boolean {
    return typeof obj === 'string';
  }

  /**
   * 判断对象是否为数字
   * 
   * @param obj 对象
   * @returns 是否为数字
   */
  public static isNumber(obj: any): boolean {
    return typeof obj === 'number' && !isNaN(obj);
  }

  /**
   * 判断对象是否为布尔值
   * 
   * @param obj 对象
   * @returns 是否为布尔值
   */
  public static isBoolean(obj: any): boolean {
    return typeof obj === 'boolean';
  }

  /**
   * 判断对象是否为日期
   * 
   * @param obj 对象
   * @returns 是否为日期
   */
  public static isDate(obj: any): boolean {
    return Object.prototype.toString.call(obj) === '[object Date]' && !isNaN(obj.getTime());
  }

  /**
   * 获取对象的类型名称
   * 
   * @param obj 对象
   * @returns 类型名称
   */
  public static getTypeName(obj: any): string {
    if (obj === null) return 'null';
    if (obj === undefined) return 'undefined';
    
    return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
  }

  /**
   * 复制对象属性
   * 
   * @param target 目标对象
   * @param source 源对象
   * @param ignoreProperties 忽略的属性列表
   * @returns 目标对象
   */
  public static copyProperties<T extends object>(target: T, source: any, ignoreProperties: string[] = []): T {
    if (!target || !source) {
      return target;
    }
    
    const ignoreSet = new Set(ignoreProperties);
    
    for (const key in source) {
      if (
        Object.prototype.hasOwnProperty.call(source, key) && 
        !ignoreSet.has(key) &&
        source[key] !== undefined
      ) {
        (target as any)[key] = source[key];
      }
    }
    
    return target;
  }

  /**
   * 对象深拷贝
   * 
   * @param obj 源对象
   * @returns 拷贝后的对象
   */
  public static deepClone<T>(obj: T): T {
    if (obj === null || typeof obj !== 'object') {
      return obj;
    }
    
    if (obj instanceof Date) {
      return new Date(obj.getTime()) as any;
    }
    
    if (obj instanceof RegExp) {
      return new RegExp(obj) as any;
    }
    
    if (Array.isArray(obj)) {
      return obj.map(item => this.deepClone(item)) as any;
    }
    
    const cloned: any = {};
    for (const key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        cloned[key] = this.deepClone((obj as any)[key]);
      }
    }
    
    return cloned;
  }

  /**
   * 合并对象
   * 
   * @param target 目标对象
   * @param sources 源对象列表
   * @returns 合并后的对象
   */
  public static merge<T extends object>(target: T, ...sources: any[]): T {
    if (!target) {
      return target;
    }
    
    for (const source of sources) {
      if (source) {
        for (const key in source) {
          if (Object.prototype.hasOwnProperty.call(source, key)) {
            const sourceValue = source[key];
            const targetValue = (target as any)[key];
            
            // 如果目标和源都是对象，则递归合并
            if (this.isObject(targetValue) && this.isObject(sourceValue)) {
              (target as any)[key] = this.merge({ ...targetValue }, sourceValue);
            } else {
              (target as any)[key] = sourceValue;
            }
          }
        }
      }
    }
    
    return target;
  }

  /**
   * 判断两个对象是否相等
   * 
   * @param obj1 对象1
   * @param obj2 对象2
   * @returns 是否相等
   */
  public static equals(obj1: any, obj2: any): boolean {
    // 处理基本类型和引用相等的情况
    if (obj1 === obj2) {
      return true;
    }
    
    // 如果任一为null或undefined，则不相等
    if (obj1 === null || obj2 === null || obj1 === undefined || obj2 === undefined) {
      return false;
    }
    
    // 类型不同，不相等
    const type1 = this.getTypeName(obj1);
    const type2 = this.getTypeName(obj2);
    
    if (type1 !== type2) {
      return false;
    }
    
    // 处理日期类型
    if (obj1 instanceof Date) {
      return obj1.getTime() === obj2.getTime();
    }
    
    // 处理正则表达式
    if (obj1 instanceof RegExp) {
      return obj1.toString() === obj2.toString();
    }
    
    // 处理数组
    if (Array.isArray(obj1)) {
      if (obj1.length !== obj2.length) {
        return false;
      }
      
      for (let i = 0; i < obj1.length; i++) {
        if (!this.equals(obj1[i], obj2[i])) {
          return false;
        }
      }
      
      return true;
    }
    
    // 处理对象
    if (this.isObject(obj1)) {
      const keys1 = Object.keys(obj1);
      const keys2 = Object.keys(obj2);
      
      if (keys1.length !== keys2.length) {
        return false;
      }
      
      for (const key of keys1) {
        if (!Object.prototype.hasOwnProperty.call(obj2, key) || 
            !this.equals((obj1 as any)[key], (obj2 as any)[key])) {
          return false;
        }
      }
      
      return true;
    }
    
    // 其他情况
    return false;
  }

  /**
   * 获取对象属性值（支持深层路径）
   * 
   * @param obj 对象
   * @param path 属性路径（使用.分隔）
   * @param defaultValue 默认值
   * @returns 属性值
   */
  public static getProperty(obj: any, path: string, defaultValue: any = undefined): any {
    if (!obj || !path) {
      return defaultValue;
    }
    
    const keys = path.split('.');
    let result = obj;
    
    for (const key of keys) {
      if (result === null || result === undefined || !Object.prototype.hasOwnProperty.call(result, key)) {
        return defaultValue;
      }
      result = result[key];
    }
    
    return result === undefined ? defaultValue : result;
  }

  /**
   * 设置对象属性值（支持深层路径）
   * 
   * @param obj 对象
   * @param path 属性路径（使用.分隔）
   * @param value 属性值
   */
  public static setProperty(obj: any, path: string, value: any): void {
    if (!obj || !path) {
      return;
    }
    
    const keys = path.split('.');
    let current = obj;
    
    for (let i = 0; i < keys.length - 1; i++) {
      const key = keys[i];
      if (current[key] === undefined || current[key] === null || typeof current[key] !== 'object') {
        current[key] = {};
      }
      current = current[key];
    }
    
    current[keys[keys.length - 1]] = value;
  }

  /**
   * 移除对象中的空属性
   * 
   * @param obj 对象
   * @param deep 是否深度处理
   * @returns 处理后的对象
   */
  public static removeEmptyProperties<T extends object>(obj: T, deep: boolean = false): T {
    if (!this.isObject(obj)) {
      return obj;
    }
    
    const result = { ...obj };
    
    for (const key in result) {
      if (Object.prototype.hasOwnProperty.call(result, key)) {
        const value = (result as any)[key];
        
        if (value === null || value === undefined || value === '') {
          delete (result as any)[key];
        } else if (deep && this.isObject(value)) {
          (result as any)[key] = this.removeEmptyProperties(value, true);
          
          // 如果深度处理后对象为空，也删除该属性
          if (Object.keys((result as any)[key]).length === 0) {
            delete (result as any)[key];
          }
        } else if (deep && Array.isArray(value)) {
          if (value.length === 0) {
            delete (result as any)[key];
          } else {
            (result as any)[key] = value.map(item => 
              this.isObject(item) ? this.removeEmptyProperties(item, true) : item
            );
          }
        }
      }
    }
    
    return result;
  }

  /**
   * 对象转查询字符串
   * 
   * @param obj 对象
   * @returns 查询字符串
   */
  public static toQueryString(obj: any): string {
    if (!obj) {
      return '';
    }
    
    const parts: string[] = [];
    
    for (const key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key) && obj[key] !== undefined) {
        const value = obj[key];
        
        if (Array.isArray(value)) {
          for (const item of value) {
            parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(item))}`);
          }
        } else {
          parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
        }
      }
    }
    
    return parts.join('&');
  }

  /**
   * 查询字符串转对象
   * 
   * @param queryString 查询字符串
   * @returns 对象
   */
  public static fromQueryString(queryString: string): Record<string, string | string[]> {
    const result: Record<string, string | string[]> = {};
    
    if (!queryString) {
      return result;
    }
    
    // 去掉开头的?或#
    let search = queryString.trim();
    if (search.startsWith('?') || search.startsWith('#')) {
      search = search.substring(1);
    }
    
    const pairs = search.split('&');
    
    for (const pair of pairs) {
      if (!pair) {
        continue;
      }
      
      const [key, value] = pair.split('=').map(decodeURIComponent);
      
      if (key) {
        // 如果是数组参数（key已存在）
        if (Object.prototype.hasOwnProperty.call(result, key)) {
          const existingValue = result[key];
          
          if (Array.isArray(existingValue)) {
            existingValue.push(value || '');
          } else {
            result[key] = [existingValue, value || ''];
          }
        } else {
          result[key] = value || '';
        }
      }
    }
    
    return result;
  }

  /**
   * 选择对象中的指定属性
   * 
   * @param obj 对象
   * @param keys 要选择的属性数组
   * @returns 新对象
   */
  public static pick<T extends object, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
    if (!obj) {
      return {} as Pick<T, K>;
    }
    
    return keys.reduce((result, key) => {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        result[key] = obj[key];
      }
      return result;
    }, {} as Pick<T, K>);
  }

  /**
   * 忽略对象中的指定属性
   * 
   * @param obj 对象
   * @param keys 要忽略的属性数组
   * @returns 新对象
   */
  public static omit<T extends object, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {
    if (!obj) {
      return {} as Omit<T, K>;
    }
    
    const result = { ...obj };
    
    for (const key of keys) {
      delete result[key];
    }
    
    return result;
  }

  /**
   * 比较两个对象的差异
   * 
   * @param obj1 对象1
   * @param obj2 对象2
   * @returns 差异对象
   */
  public static diff(obj1: any, obj2: any): Record<string, { old: any; new: any }> {
    const result: Record<string, { old: any; new: any }> = {};
    
    // 检查obj1中有但在obj2中不同的属性
    if (obj1 && typeof obj1 === 'object') {
      for (const key in obj1) {
        if (Object.prototype.hasOwnProperty.call(obj1, key)) {
          // 如果obj2中没有该属性
          if (obj2 === undefined || obj2 === null || !Object.prototype.hasOwnProperty.call(obj2, key)) {
            result[key] = { old: obj1[key], new: undefined };
          }
          // 如果值不同
          else if (!this.equals(obj1[key], obj2[key])) {
            result[key] = { old: obj1[key], new: obj2[key] };
          }
        }
      }
    }
    
    // 检查obj2中有但在obj1中没有的属性
    if (obj2 && typeof obj2 === 'object') {
      for (const key in obj2) {
        if (
          Object.prototype.hasOwnProperty.call(obj2, key) &&
          (obj1 === undefined || obj1 === null || !Object.prototype.hasOwnProperty.call(obj1, key))
        ) {
          result[key] = { old: undefined, new: obj2[key] };
        }
      }
    }
    
    return result;
  }

  /**
   * 将嵌套对象扁平化为单层对象
   * 
   * @param obj 嵌套对象
   * @param prefix 属性前缀
   * @param separator 分隔符
   * @returns 扁平化后的对象
   */
  public static flatten(
    obj: any, 
    prefix: string = '', 
    separator: string = '.'
  ): Record<string, any> {
    const result: Record<string, any> = {};
    
    if (!this.isObject(obj) && !Array.isArray(obj)) {
      if (prefix) {
        result[prefix] = obj;
      }
      return result;
    }
    
    for (const key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        const newKey = prefix ? `${prefix}${separator}${key}` : key;
        const value = obj[key];
        
        if (this.isObject(value) || Array.isArray(value)) {
          Object.assign(result, this.flatten(value, newKey, separator));
        } else {
          result[newKey] = value;
        }
      }
    }
    
    return result;
  }

  /**
   * 安全解析JSON字符串
   * 
   * @param jsonString JSON字符串
   * @param defaultValue 解析失败时的默认值
   * @returns 解析后的对象
   */
  public static parseJSON<T = any>(jsonString: string, defaultValue: any = {}): T {
    if (!jsonString) {
      return defaultValue as T;
    }
    
    try {
      return JSON.parse(jsonString) as T;
    } catch (error) {
      return defaultValue as T;
    }
  }

  /**
   * 安全将对象转换为JSON字符串
   * 
   * @param obj 对象
   * @param defaultValue 转换失败时的默认值
   * @returns JSON字符串
   */
  public static stringify(obj: any, defaultValue: string = '{}'): string {
    if (obj === undefined || obj === null) {
      return defaultValue;
    }
    
    try {
      return JSON.stringify(obj);
    } catch (error) {
      return defaultValue;
    }
  }
} 